/*
    在父元素区域任意拖拽元素。

    思路：
        1、设置需要拖拽的元素为absolute，其父元素为relative。
        2、鼠标按下(onmousedown)时记录目标元素当前的 left 和 top 值。
        3、鼠标移动(onmousemove)时计算每次移动的横向距离和纵向距离的变化值，并改变元素的 left 和 top 值
        4、鼠标松开(onmouseup)时完成一次拖拽
    
    使用：在 Dom 上加上 v-draggable 即可
    <div v-draggable></div>
*/

import type { Directive } from "vue";
interface ElType extends HTMLElement {
    parentNode: any;
}

const mounted = (drag_dom: ElType) => {
    drag_dom.style.cursor = "move";
    drag_dom.style.position = "absolute";
    drag_dom.style.userSelect = "none";

    drag_dom.onmousedown = function (e) {
        // 按下鼠标时，鼠标相对于被拖拽元素的坐标
        const disX = e.clientX - drag_dom.offsetLeft;
        const disY = e.clientY - drag_dom.offsetTop;

        // 获取容器dom
        const container_dom = drag_dom.parentNode;
        document.onmousemove = function (e) {
            // 用鼠标的位置减去鼠标相对元素的位置，得到元素的位置
            const left = e.clientX - disX;
            const top = e.clientY - disY;

            // 在容器范围内移动时，被拖拽元素的最大left值
            const leftMax =
                container_dom.offsetLeft +
                (container_dom.clientWidth - drag_dom.clientWidth);

            // 在容器范围内移动时，被拖拽元素的最小left值
            const leftMin = container_dom.offsetLeft;

            if (left > leftMax) {
                drag_dom.style.left = leftMax + "px";
            } else if (left < leftMin) {
                drag_dom.style.left = leftMin + "px";
            } else {
                drag_dom.style.left = left + "px";
            }

            // 在容器范围内移动时，被拖拽元素的最大left值
            const topMax =
                container_dom.offsetTop +
                (container_dom.clientHeight - drag_dom.clientHeight);

            // 在容器范围内移动时，被拖拽元素的最小left值
            const topMin = container_dom.offsetTop;

            if (top > topMax) {
                drag_dom.style.top = topMax + "px";
            } else if (top < topMin) {
                drag_dom.style.top = topMin + "px";
            } else {
                drag_dom.style.top = top + "px";
            }
        };
        document.onmouseup = function () {
            document.onmousemove = document.onmouseup = null;
        };
    };
};

const draggable: Directive = {
    mounted,
};

export default draggable;
